/**
 * @file lv_toolbar.c
 *
 */

/*********************
 *      INCLUDES
 *********************/
#include "lv_toolbar_private.h"

#include "../../../lvgl/src/core/lv_obj_class_private.h"
#include "../../../lvgl/src/layouts/flex/lv_flex.h"
#include "../../../lvgl/src/display/lv_display.h"

#if LV_USE_TOOLBAR

/*********************
 *      DEFINES
 *********************/
#define MY_CLASS        (&lv_toolbar_class)

/**********************
 *      TYPEDEFS
 **********************/

/**********************
 *  STATIC PROTOTYPES
 **********************/
static void update_size(lv_obj_t * obj);
static void lv_toolbar_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);


/**********************
 *  STATIC VARIABLES
 **********************/
const lv_obj_class_t lv_toolbar_class = {
    .constructor_cb = lv_toolbar_constructor,
    .base_class = &lv_obj_class,
    .width_def = LV_SIZE_CONTENT,
    .height_def = LV_SIZE_CONTENT,
    .instance_size = sizeof(lv_toolbar_t),
    .name = "lv_toolbar",
};

/**********************
 *      MACROS
 **********************/

/**********************
 *   GLOBAL FUNCTIONS
 **********************/

lv_obj_t * lv_toolbar_create(lv_obj_t * parent)
{
    LV_LOG_INFO("begin");
    lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
    lv_obj_class_init_obj(obj);
    return obj;
}

void lv_toolbar_update(lv_obj_t * obj)
{
    LV_ASSERT_OBJ(obj, MY_CLASS);
    lv_toolbar_t * toolbar = (lv_toolbar_t *)obj;
    uint32_t child_count = lv_obj_get_child_count(obj);
    if(!child_count) return;
    update_size(obj);

    lv_obj_t * child = lv_obj_get_child(obj, 0);
    lv_toolbar_align_t align = toolbar->align;
    lv_align_t next_align;
    uint32_t next_x_spacing = 0;
    uint32_t next_y_spacing = 0;

    if(toolbar->align == LV_TOOLBAR_ALIGN_RIGHT) {
        //lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_ROW);
        lv_obj_align(child, LV_ALIGN_LEFT_MID, toolbar->start_spacing, 0);
        next_align = LV_ALIGN_OUT_RIGHT_MID;
        next_x_spacing = toolbar->mid_spacing;
    }
    else if(toolbar->align == LV_TOOLBAR_ALIGN_LEFT) {
        //lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_ROW);
        lv_obj_align(child, LV_ALIGN_RIGHT_MID, -toolbar->start_spacing, 0);
        next_align = LV_ALIGN_OUT_LEFT_MID;
        next_x_spacing = -toolbar->mid_spacing;
    }
    if(toolbar->align == LV_TOOLBAR_ALIGN_BOTTOM) {
        //lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_COLUMN);
        lv_obj_align(child, LV_ALIGN_TOP_MID, 0, toolbar->start_spacing);
        next_align = LV_ALIGN_OUT_BOTTOM_MID;
        next_y_spacing = toolbar->mid_spacing;
    }
    else if(toolbar->align == LV_TOOLBAR_ALIGN_TOP) {
        //lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_COLUMN);
        lv_obj_align(child, LV_ALIGN_BOTTOM_MID, 0, -toolbar->start_spacing);
        next_align = LV_ALIGN_OUT_TOP_MID;
        next_y_spacing = -toolbar->mid_spacing;
    }

    for(uint32_t i = 1; i < child_count; i++) {
        lv_obj_t * next_child = lv_obj_get_child(obj, i);
        lv_obj_align_to(next_child, child, next_align, next_x_spacing, next_y_spacing);
        child = next_child;
    }
    lv_obj_invalidate(obj);
}

void lv_toolbar_set_align(lv_obj_t * obj, lv_toolbar_align_t align)
{
    LV_ASSERT_OBJ(obj, MY_CLASS);
    lv_toolbar_t * toolbar = (lv_toolbar_t *)obj;
    toolbar->align = align;
}

void lv_toolbar_set_start_spacing(lv_obj_t * obj, uint8_t start_spacing)
{
    LV_ASSERT_OBJ(obj, MY_CLASS);
    lv_toolbar_t * toolbar = (lv_toolbar_t *)obj;
    toolbar->start_spacing = start_spacing;
}

void lv_toolbar_set_mid_spacing(lv_obj_t * obj, uint8_t mid_spacing)
{
    LV_ASSERT_OBJ(obj, MY_CLASS);
    lv_toolbar_t * toolbar = (lv_toolbar_t *)obj;
    toolbar->mid_spacing = mid_spacing;
}

lv_obj_t * lv_toolbar_add(lv_obj_t * toolbar, uint8_t pos)
{
  LV_ASSERT_OBJ(toolbar, MY_CLASS);
  lv_obj_t *obj  = lv_obj_create(toolbar);
  uint32_t count = lv_obj_get_child_count(toolbar);
  if(pos < count){
    lv_obj_t * org_obj  = lv_obj_get_child(toolbar, pos);
    lv_obj_swap(obj, org_obj);
  }
  return obj;
}

void lv_toolbar_remove(lv_obj_t * toolbar, uint8_t pos)
{
    LV_ASSERT_OBJ(toolbar, MY_CLASS);
    lv_obj_t * obj  = lv_obj_get_child(toolbar, pos);
    lv_obj_delete(obj);
}

lv_toolbar_align_t lv_toolbar_get_align(const lv_obj_t * obj)
{
    LV_ASSERT_OBJ(obj, MY_CLASS);
    lv_toolbar_t * toolbar = (lv_toolbar_t *)obj;
    return toolbar->align;
}

uint8_t lv_toolbar_get_start_spacing(const lv_obj_t * obj)
{
    LV_ASSERT_OBJ(obj, MY_CLASS);
    lv_toolbar_t * toolbar = (lv_toolbar_t *)obj;
    return toolbar->start_spacing;
}

uint8_t lv_toolbar_get_mid_spacing(const lv_obj_t * obj)
{
    LV_ASSERT_OBJ(obj, MY_CLASS);
    lv_toolbar_t * toolbar = (lv_toolbar_t *)obj;
    return toolbar->mid_spacing;
}

lv_obj_t * lv_toolbar_get_obj(lv_obj_t * toolbar, uint8_t pos)
{
    LV_ASSERT_OBJ(toolbar, MY_CLASS);
    return lv_obj_get_child(toolbar, pos);
}

uint32_t lv_toolbar_get_count(lv_obj_t * toolbar)
{
    LV_ASSERT_OBJ(toolbar, MY_CLASS);
    return lv_obj_get_child_count(toolbar);
}

/**********************
 *   STATIC FUNCTIONS
 **********************/

static void update_size(lv_obj_t * obj)
{
  LV_ASSERT_OBJ(obj, MY_CLASS);
  lv_toolbar_t * toolbar = (lv_toolbar_t *)obj;

  uint32_t child_count = lv_obj_get_child_count(obj);
  uint32_t w, h;
  bool hori;
  if((toolbar->align == LV_TOOLBAR_ALIGN_RIGHT) ||  (toolbar->align == LV_TOOLBAR_ALIGN_LEFT)){
      w = toolbar->start_spacing + (child_count - 1) * toolbar->mid_spacing;
      h = 0;
      hori = true;
  }
  else{
      w = 0;
      h = toolbar->start_spacing + (child_count - 1) * toolbar->mid_spacing;
      hori = false;
  }

  for(uint32_t i = 0; i < child_count; i++) {
      lv_obj_t * child = lv_obj_get_child(obj, i);
      lv_obj_update_layout(child);
      uint32_t cw = lv_obj_get_width(child);
      uint32_t ch = lv_obj_get_height(child);
      if(hori) {
        w += cw;
        if(ch > h) h = ch;
      }
      else {
        h += ch;
        if(cw > w) w = cw;
      }
  }
  lv_obj_set_width(obj, w);
  lv_obj_set_height(obj, h);
  lv_obj_update_layout(obj);
}

static void lv_toolbar_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
{
    LV_UNUSED(class_p);
    LV_TRACE_OBJ_CREATE("begin");

    lv_toolbar_t * toolbar = (lv_toolbar_t *)obj;
    toolbar->align = LV_TOOLBAR_ALIGN_RIGHT;
    toolbar->start_spacing = 0;
    toolbar->mid_spacing = 0;
    LV_TRACE_OBJ_CREATE("finished");
}

#endif /*LV_USE_TOOLBAR*/
